/**
 * 微信小程序网络请求工具类
 */

const { showToast, showLoading, hideLoading } = require('./util')

// 配置常量
const CONFIG = {
  // API基础地址
  BASE_URL: 'https://api.example.com',
  // 请求超时时间
  TIMEOUT: 10000,
  // 重试次数
  RETRY_COUNT: 3,
  // 重试延迟时间
  RETRY_DELAY: 1000
}

// 请求状态码
const STATUS_CODE = {
  SUCCESS: 200,
  UNAUTHORIZED: 401,
  FORBIDDEN: 403,
  NOT_FOUND: 404,
  SERVER_ERROR: 500
}

// 错误信息映射
const ERROR_MESSAGES = {
  [STATUS_CODE.UNAUTHORIZED]: '登录已过期，请重新登录',
  [STATUS_CODE.FORBIDDEN]: '没有权限访问',
  [STATUS_CODE.NOT_FOUND]: '请求的资源不存在',
  [STATUS_CODE.SERVER_ERROR]: '服务器内部错误',
  'network': '网络连接失败，请检查网络设置',
  'timeout': '请求超时，请稍后重试',
  'unknown': '未知错误，请稍后重试'
}

/**
 * 请求拦截器
 */
class RequestInterceptor {
  constructor() {
    this.requestInterceptors = []
    this.responseInterceptors = []
  }

  /**
   * 添加请求拦截器
   * @param {Function} fulfilled 成功回调
   * @param {Function} rejected 失败回调
   */
  addRequestInterceptor(fulfilled, rejected) {
    this.requestInterceptors.push({ fulfilled, rejected })
  }

  /**
   * 添加响应拦截器
   * @param {Function} fulfilled 成功回调
   * @param {Function} rejected 失败回调
   */
  addResponseInterceptor(fulfilled, rejected) {
    this.responseInterceptors.push({ fulfilled, rejected })
  }

  /**
   * 执行请求拦截器
   * @param {object} config 请求配置
   * @returns {object} 处理后的配置
   */
  async executeRequestInterceptors(config) {
    let processedConfig = config
    
    for (let interceptor of this.requestInterceptors) {
      try {
        if (interceptor.fulfilled) {
          processedConfig = await interceptor.fulfilled(processedConfig)
        }
      } catch (error) {
        if (interceptor.rejected) {
          return await interceptor.rejected(error)
        }
        throw error
      }
    }
    
    return processedConfig
  }

  /**
   * 执行响应拦截器
   * @param {object} response 响应数据
   * @returns {object} 处理后的响应
   */
  async executeResponseInterceptors(response) {
    let processedResponse = response
    
    for (let interceptor of this.responseInterceptors) {
      try {
        if (interceptor.fulfilled) {
          processedResponse = await interceptor.fulfilled(processedResponse)
        }
      } catch (error) {
        if (interceptor.rejected) {
          return await interceptor.rejected(error)
        }
        throw error
      }
    }
    
    return processedResponse
  }
}

/**
 * HTTP请求类
 */
class HttpRequest {
  constructor() {
    this.interceptor = new RequestInterceptor()
    this.pendingRequests = new Map()
    this.setupDefaultInterceptors()
  }

  /**
   * 设置默认拦截器
   */
  setupDefaultInterceptors() {
    // 请求拦截器：添加token
    this.interceptor.addRequestInterceptor(
      (config) => {
        // 添加认证token
        const token = wx.getStorageSync('token')
        if (token) {
          config.header = config.header || {}
          config.header.Authorization = `Bearer ${token}`
        }
        
        // 添加公共参数
        config.header = {
          'Content-Type': 'application/json',
          ...config.header
        }
        
        return config
      },
      (error) => {
        return Promise.reject(error)
      }
    )

    // 响应拦截器：处理通用错误
    this.interceptor.addResponseInterceptor(
      (response) => {
        const { data, statusCode } = response
        
        // 处理业务错误
        if (data && data.code !== undefined) {
          if (data.code === 0 || data.code === 200) {
            return data.data || data
          } else {
            const error = new Error(data.message || '请求失败')
            error.code = data.code
            error.response = response
            throw error
          }
        }
        
        // 处理HTTP状态码
        if (statusCode === STATUS_CODE.SUCCESS) {
          return data
        } else {
          const error = new Error(ERROR_MESSAGES[statusCode] || '请求失败')
          error.statusCode = statusCode
          error.response = response
          throw error
        }
      },
      (error) => {
        // 处理网络错误
        if (error.errMsg) {
          if (error.errMsg.includes('timeout')) {
            error.message = ERROR_MESSAGES.timeout
          } else if (error.errMsg.includes('fail')) {
            error.message = ERROR_MESSAGES.network
          }
        }
        
        // 处理401错误：跳转登录
        if (error.statusCode === STATUS_CODE.UNAUTHORIZED) {
          this.handleUnauthorized()
        }
        
        return Promise.reject(error)
      }
    )
  }

  /**
   * 处理未授权错误
   */
  handleUnauthorized() {
    // 清除token
    wx.removeStorageSync('token')
    wx.removeStorageSync('userInfo')
    
    // 显示提示
    showToast('登录已过期，请重新登录')
    
    // 跳转到登录页
    setTimeout(() => {
      wx.reLaunch({
        url: '/pages/login/login'
      })
    }, 1500)
  }

  /**
   * 生成请求key
   * @param {object} config 请求配置
   * @returns {string} 请求key
   */
  generateRequestKey(config) {
    const { url, method, data } = config
    return `${method}_${url}_${JSON.stringify(data || {})}`
  }

  /**
   * 取消重复请求
   * @param {object} config 请求配置
   */
  cancelDuplicateRequest(config) {
    const requestKey = this.generateRequestKey(config)
    
    if (this.pendingRequests.has(requestKey)) {
      const requestTask = this.pendingRequests.get(requestKey)
      requestTask.abort()
      this.pendingRequests.delete(requestKey)
    }
    
    return requestKey
  }

  /**
   * 发送请求
   * @param {object} config 请求配置
   * @returns {Promise} 请求Promise
   */
  async request(config) {
    try {
      // 执行请求拦截器
      config = await this.interceptor.executeRequestInterceptors(config)
      
      // 处理URL
      if (!config.url.startsWith('http')) {
        config.url = CONFIG.BASE_URL + config.url
      }
      
      // 设置默认值
      config.method = config.method || 'GET'
      config.timeout = config.timeout || CONFIG.TIMEOUT
      
      // 取消重复请求
      const requestKey = this.cancelDuplicateRequest(config)
      
      // 显示加载提示
      if (config.loading !== false) {
        showLoading(config.loadingText)
      }
      
      // 发送请求
      const requestTask = wx.request({
        ...config,
        success: () => {}, // 由Promise处理
        fail: () => {} // 由Promise处理
      })
      
      // 保存请求任务
      this.pendingRequests.set(requestKey, requestTask)
      
      // 包装为Promise
      const response = await new Promise((resolve, reject) => {
        requestTask.onHeadersReceived = (res) => {
          // 处理响应头
        }
        
        requestTask.offHeadersReceived = () => {
          // 移除响应头监听
        }
        
        // 重写success和fail回调
        const originalSuccess = requestTask.success
        const originalFail = requestTask.fail
        
        requestTask.success = (res) => {
          this.pendingRequests.delete(requestKey)
          resolve(res)
        }
        
        requestTask.fail = (error) => {
          this.pendingRequests.delete(requestKey)
          reject(error)
        }
      })
      
      // 隐藏加载提示
      if (config.loading !== false) {
        hideLoading()
      }
      
      // 执行响应拦截器
      return await this.interceptor.executeResponseInterceptors(response)
      
    } catch (error) {
      // 隐藏加载提示
      if (config.loading !== false) {
        hideLoading()
      }
      
      // 显示错误提示
      if (config.showError !== false) {
        showToast(error.message || ERROR_MESSAGES.unknown)
      }
      
      throw error
    }
  }

  /**
   * 重试请求
   * @param {object} config 请求配置
   * @param {number} retryCount 重试次数
   * @returns {Promise} 请求Promise
   */
  async retryRequest(config, retryCount = CONFIG.RETRY_COUNT) {
    try {
      return await this.request(config)
    } catch (error) {
      if (retryCount > 0 && this.shouldRetry(error)) {
        await this.delay(CONFIG.RETRY_DELAY)
        return this.retryRequest(config, retryCount - 1)
      }
      throw error
    }
  }

  /**
   * 判断是否应该重试
   * @param {Error} error 错误对象
   * @returns {boolean} 是否重试
   */
  shouldRetry(error) {
    // 网络错误或超时错误可以重试
    return error.errMsg && (
      error.errMsg.includes('timeout') ||
      error.errMsg.includes('fail')
    )
  }

  /**
   * 延迟函数
   * @param {number} ms 延迟时间（毫秒）
   * @returns {Promise} Promise对象
   */
  delay(ms) {
    return new Promise(resolve => setTimeout(resolve, ms))
  }

  /**
   * GET请求
   * @param {string} url 请求地址
   * @param {object} params 请求参数
   * @param {object} config 请求配置
   * @returns {Promise} 请求Promise
   */
  get(url, params = {}, config = {}) {
    return this.request({
      url,
      method: 'GET',
      data: params,
      ...config
    })
  }

  /**
   * POST请求
   * @param {string} url 请求地址
   * @param {object} data 请求数据
   * @param {object} config 请求配置
   * @returns {Promise} 请求Promise
   */
  post(url, data = {}, config = {}) {
    return this.request({
      url,
      method: 'POST',
      data,
      ...config
    })
  }

  /**
   * PUT请求
   * @param {string} url 请求地址
   * @param {object} data 请求数据
   * @param {object} config 请求配置
   * @returns {Promise} 请求Promise
   */
  put(url, data = {}, config = {}) {
    return this.request({
      url,
      method: 'PUT',
      data,
      ...config
    })
  }

  /**
   * DELETE请求
   * @param {string} url 请求地址
   * @param {object} config 请求配置
   * @returns {Promise} 请求Promise
   */
  delete(url, config = {}) {
    return this.request({
      url,
      method: 'DELETE',
      ...config
    })
  }

  /**
   * 上传文件
   * @param {string} url 上传地址
   * @param {string} filePath 文件路径
   * @param {object} formData 表单数据
   * @param {object} config 配置
   * @returns {Promise} 上传Promise
   */
  upload(url, filePath, formData = {}, config = {}) {
    return new Promise((resolve, reject) => {
      // 处理URL
      if (!url.startsWith('http')) {
        url = CONFIG.BASE_URL + url
      }
      
      // 添加token
      const token = wx.getStorageSync('token')
      const header = {
        ...config.header
      }
      if (token) {
        header.Authorization = `Bearer ${token}`
      }
      
      // 显示加载提示
      if (config.loading !== false) {
        showLoading('上传中...')
      }
      
      const uploadTask = wx.uploadFile({
        url,
        filePath,
        name: config.name || 'file',
        formData,
        header,
        success: (res) => {
          hideLoading()
          try {
            const data = JSON.parse(res.data)
            if (data.code === 0 || data.code === 200) {
              resolve(data.data || data)
            } else {
              reject(new Error(data.message || '上传失败'))
            }
          } catch (error) {
            reject(new Error('响应数据格式错误'))
          }
        },
        fail: (error) => {
          hideLoading()
          reject(error)
        }
      })
      
      // 监听上传进度
      if (config.onProgress) {
        uploadTask.onProgressUpdate(config.onProgress)
      }
    })
  }

  /**
   * 下载文件
   * @param {string} url 下载地址
   * @param {object} config 配置
   * @returns {Promise} 下载Promise
   */
  download(url, config = {}) {
    return new Promise((resolve, reject) => {
      // 处理URL
      if (!url.startsWith('http')) {
        url = CONFIG.BASE_URL + url
      }
      
      // 添加token
      const token = wx.getStorageSync('token')
      const header = {
        ...config.header
      }
      if (token) {
        header.Authorization = `Bearer ${token}`
      }
      
      // 显示加载提示
      if (config.loading !== false) {
        showLoading('下载中...')
      }
      
      const downloadTask = wx.downloadFile({
        url,
        header,
        success: (res) => {
          hideLoading()
          if (res.statusCode === 200) {
            resolve(res.tempFilePath)
          } else {
            reject(new Error('下载失败'))
          }
        },
        fail: (error) => {
          hideLoading()
          reject(error)
        }
      })
      
      // 监听下载进度
      if (config.onProgress) {
        downloadTask.onProgressUpdate(config.onProgress)
      }
    })
  }
}

// 创建实例
const http = new HttpRequest()

// 导出实例和类
module.exports = {
  http,
  HttpRequest,
  CONFIG,
  STATUS_CODE,
  ERROR_MESSAGES
}